package cn.zzp.basic.interceptor;

import cn.zzp.basic.jwt.LoginData;
import cn.zzp.basic.jwt.Payload;
import cn.zzp.basic.jwt.RsaUtils;
import cn.zzp.org.mapper.EmployeeMapper;
import cn.zzp.system.annotation.PreAuthorize;
import cn.zzp.user.domain.LoginInfo;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.PublicKey;
import java.util.List;

import static cn.zzp.basic.jwt.JwtUtils.getInfoFromToken;

/**
 * @author Administrator
 * @description: 登录拦截器
 * @date 2022/7/30 17:15
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {


    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 取出token,前端将token存入请求头内，直接调方法取
        String jwtToken = request.getHeader("token");

        if (jwtToken != null) {
            // 2. 从redis中去取
            //Object obj = redisTemplate.opsForValue().get(token);

            // 解密
            // 获取公钥
            PublicKey publicKey = RsaUtils.getPublicKey(RsaUtils.class.getClassLoader().getResource("auth_rsa.pub").getFile());

            try {
                Payload<LoginData> payload = getInfoFromToken(jwtToken, publicKey, LoginData.class);

                //刷新过期时间不做 @TODO - 可以用redis保存token串
                if (payload != null) {//登录成功，而且没有过期
                    //5.如获取登录信息对象
                    LoginInfo loginInfo = payload.getLoginData().getLoginInfo();
                    //6.如果是用户 - 放行
                    if (loginInfo.getType() == 1) { return true; }
                    //7.如果是后端管理员 - 验证权限【后端管理员 - 角色不一样 - 权限不一样】
                    //8.获取当前接口上注解里的sn - handler - 获取注解@PreAuthorize - 获取注解里面的sn
                    HandlerMethod handlerMethod = (HandlerMethod) handler; //就是接收请求的接口 - 方法
                    //System.out.println(handlerMethod.getMethod().getName());//获取接口名
                    PreAuthorize annotation = handlerMethod.getMethodAnnotation(PreAuthorize.class);
                    if (annotation == null) {//如果当前接口方法上没有这个注解 - 不需要校验权限 - 直接放行
                        return true;
                    } else {
                        String sn = annotation.sn();
                        //9.根据loginInfo_id获取当前登录人的所有权限 - sn
                        List<String> sns = employeeMapper.queryPermissionSnByLoginInfoId(loginInfo.getId());
                        if (sns.contains(sn)) {//有权限
                            return true;
                        } else {//else会经过后置拦截器，可以在axios后置拦截器中判断弹出错误框
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().println("{\"success\":false,\"message\":\"noPermission\"}");
                            return false;
                        }
                    }
                }
            } catch (ExpiredJwtException e){ // 如果过期了
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"success\":false,\"message\":\"timeout\"}");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 未登录需要返回给前端json响应结果{"success":false,"message":"noLogin"}
        // 这里只能使用原始方法
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"success\":false,\"message\":\"noLogin\"}");

        return false;
    }
}
